namespace Nes
{
    export class Tile
    {
        //由于直接操作最小单位就是byte，所以用u8，直接索引到NES调色板颜色
        //有子调色板时，更容易控制一个tile限制使用几种颜色
        //故而 Tile有两种模式
        //1.packed模式，有一个子调色板，pixel里存的是子调色板索引，需要再次索引到颜色
        //2.unpacked模式，没有子调色板，pixel里存的是颜色索引
        size: number;
        pixel: Uint8Array;//8x8 title，
        colorCount: number;//=0 表示不需要子调色板，直接映射到nes索引色
        subPalette: Uint8Array;//子调色板
        constructor(size: number, _colorCount: number = 0)
        {
            this.size = size;
            this.pixel = new Uint8Array(size * size);
            this.colorCount = _colorCount;
            if (this.colorCount == 0)
                this.subPalette = new Uint8Array(0);
            else
                this.subPalette = new Uint8Array(_colorCount);
        }
        unpack(): Tile
        {
            if (this.colorCount == 0)//unpacked 
                return this;


            var t = new Tile(this.size, 0);

            for (let i = 0; i < this.pixel.length; i++)
            {
                var palindex = this.pixel[i];
                t.pixel[i] = this.subPalette[palindex];
            }
            return t;
        }
        pack(): Tile
        {
            if (this.colorCount > 0)//packed 
                return this;
            let subindex: { [id: number]: number } = {};
            let count = 0;
            for (let i = 0; i < this.pixel.length; i++)
            {
                if (subindex[this.pixel[i]] == undefined)
                {
                    subindex[this.pixel[i]] = count;
                    count++;
                }
            }

            var t = new Tile(this.size, count);
            for (let i in subindex)
            {
                var color = <number><unknown>i;
                var palindex = subindex[color];
                t.subPalette[palindex] = color;
            }
            for (let i = 0; i < this.pixel.length; i++)
            {
                var palindex = subindex[this.pixel[i]];
                t.pixel[i] = palindex;
            }
            return t;
        }
        GetColor(x: number, y: number): number
        {
            if (this.colorCount == 0)
                return this.pixel[y * this.size + x];
            else
                return this.subPalette[this.pixel[y * this.size + x]];
        }
    }
    export class Chr
    {
        tiles: Tile[] = [];
        constructor()
        {

        }
        LoadFromChr(data: Uint8Array): void
        {
            //固定1k個
            for (let i = 0; i < 1024; i++)
            {
                let t = new Tile(8, 4);
                t.subPalette[0]=0x0f;
                t.subPalette[1]=0x05;
                t.subPalette[2]=0x37;
                t.subPalette[3]=0x0b;
                for (let y = 0; y < 8; y++)
                {
                    var line = data[i * 16 + y];
                    var line1 = data[i * 16 + 8 + y];
                    for (let x = 0; x < 8; x++)
                    {
                        let index = ((line1 >> (7-x)) & 0x01) * 2 + ((line >> (7-x)) & 0x01);
                        t.pixel[y * 8 + x] = index;
                    }
                }
                this.tiles.push(t);
            }
        }
        ToTexture(webgl: WebGLRenderingContext, pal: Palette): lighttool.spriteTexture
        {
            let charSize = 16;
            while (this.tiles.length > (charSize * charSize))
            {
                charSize *= 2;
            }
            if (charSize > 128)
                throw "too big";
            var data = new Uint8Array(charSize * 8 * charSize * 8 * 4);
            for (let i = 0; i < this.tiles.length; i++)
            {
                let x = (i % charSize) | 0;
                let y = (i / charSize) | 0;
                for (let sy = 0; sy < 8; sy++)
                {
                    for (let sx = 0; sx < 8; sx++)
                    {
                        let colorindex = this.tiles[i].GetColor(sx, sy);
                        var ci = pal.colors[colorindex];
                        let pixelindex = (y * 8 + sy) * charSize*8 + x * 8 + sx;
                        data[pixelindex * 4 + 0] = ci.r * 255;
                        data[pixelindex * 4 + 1] = ci.g * 255;
                        data[pixelindex * 4 + 2] = ci.b * 255;
                        data[pixelindex * 4 + 3] = ci.a * 255;
                    }
                }

            }
            var tex = lighttool.spriteTexture.FromUInt8Array(webgl, data, charSize * 8, charSize * 8, lighttool.textureformat.RGBA, false, false);
            return tex;
        }
    }
}